package com.springboot.controller;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.springboot.common.Result;
import com.springboot.exception.CustomException;

import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 文件上传控制器
 * 上传单文件最大支持20MB（由 application.yml 配置 spring.servlet.multipart.max-file-size、file.max-size 控制）
 */
@CrossOrigin
@RestController
@RequestMapping("/files")
public class FileController {

    @Resource
    private HttpServletRequest request;

    @Value("${file.upload.path:/file}")
    private String uploadBasePath;

    @Value("${file.max-size:20971520}") // 20MB，需与 application.yml 保持一致
    private long maxFileSize;

    private static final Set<String> ALLOWED_EXTENSIONS = new HashSet<>(Arrays.asList(
            "jpg", "jpeg", "png", "gif", "pdf", "doc", "docx", "xls", "xlsx"
    ));

    /**
     * 文件上传
     * @param file 文件
     * @param path 自定义路径（支持多级目录，如：product/images/2024/03）
     */
    @PostMapping("/upload")
    public Result upload(MultipartFile file, @RequestParam(required = false) String path) {
        synchronized (FileController.class) {
            // 1. 参数校验
            if (file == null || file.isEmpty()) {
                throw new CustomException("文件不能为空");
            }

            // 2. 文件大小校验
            if (file.getSize() > maxFileSize) {
                throw new CustomException("文件大小超出限制");
            }

            // 3. 文件类型校验
            String originalFilename = file.getOriginalFilename();
            String extension = FileUtil.extName(originalFilename);
            if (!ALLOWED_EXTENSIONS.contains(extension.toLowerCase())) {
                throw new CustomException("不支持的文件类型");
            }

            // 4. 构建上传路径
            String uploadPath = System.getProperty("user.dir") + uploadBasePath;
            if (StrUtil.isNotEmpty(path)) {
                uploadPath += "/" + path;
            }

            try {
                // 5. 创建目录
                File uploadDir = new File(uploadPath);
                if (!uploadDir.exists()) {
                    if (!uploadDir.mkdirs()) {
                        throw new CustomException("创建目录失败");
                    }
                }

                // 6. 生成文件名（使用时间戳+随机数）
                String fileName = System.currentTimeMillis() + "_" + (int)(Math.random() * 1000) + "." + extension;
                String fullPath = uploadPath + "/" + fileName;

                // 7. 保存文件
                FileUtil.writeBytes(file.getBytes(), fullPath);
                
                // 8. 返回相对路径
                Object relativePath = (StrUtil.isNotEmpty(path) ? path + "/" : "") + fileName;
                return Result.success(relativePath);
            } catch (Exception e) {
                throw new CustomException("文件上传失败: " + e.getMessage());
            }
        }
    }

    /**
     * 批量文件上传
     * @param files 文件数组
     * @param path 自定义路径（支持多级目录，如：product/images/2024/03）
     */
    @PostMapping("/batchUpload")
    public Result batchUpload(@RequestParam("files") MultipartFile[] files, @RequestParam(required = false) String path) {
        synchronized (FileController.class) {
            // 1. 参数校验
            if (files == null || files.length == 0) {
                throw new CustomException("文件不能为空");
            }

            List<String> uploadedPaths = new ArrayList<>();

            // 2. 遍历处理每个文件
            for (MultipartFile file : files) {
                try {
                    // 检查文件是否为空
                    if (file.isEmpty()) {
                        continue; // 跳过空文件
                    }

                    // 文件大小校验
                    if (file.getSize() > maxFileSize) {
                        throw new CustomException("文件大小超出限制: " + file.getOriginalFilename());
                    }

                    // 文件类型校验
                    String originalFilename = file.getOriginalFilename();
                    String extension = FileUtil.extName(originalFilename);
                    if (!ALLOWED_EXTENSIONS.contains(extension.toLowerCase())) {
                        throw new CustomException("不支持的文件类型: " + originalFilename);
                    }

                    // 构建上传路径
                    String uploadPath = System.getProperty("user.dir") + uploadBasePath;
                    if (StrUtil.isNotEmpty(path)) {
                        uploadPath += "/" + path;
                    }

                    // 创建目录
                    File uploadDir = new File(uploadPath);
                    if (!uploadDir.exists()) {
                        if (!uploadDir.mkdirs()) {
                            throw new CustomException("创建目录失败");
                        }
                    }

                    // 生成文件名（使用时间戳+随机数）
                    String fileName = System.currentTimeMillis() + "_" + (int) (Math.random() * 1000) + "." + extension;
                    String fullPath = uploadPath + "/" + fileName;

                    // 保存文件
                    FileUtil.writeBytes(file.getBytes(), fullPath);

                    // 添加相对路径到结果列表
                    String relativePath = (StrUtil.isNotEmpty(path) ? path + "/" : "") + fileName;
                    uploadedPaths.add(relativePath);
                } catch (Exception e) {
                    throw new CustomException("批量文件上传失败: " + e.getMessage());
                }
            }

            if (uploadedPaths.isEmpty()) {
                throw new CustomException("没有文件被成功上传");
            }

            // 返回上传成功的文件路径列表
            return Result.success(uploadedPaths);
        }
    }

    /**
     * 获取文件
     */
    @ResponseBody
    @GetMapping("/get/**")
    public ResponseEntity<byte[]> getFile() {
        try {
            // 获取完整的请求路径
            String requestPath = request.getRequestURI();
            // 移除 /api/files/get/ 前缀
            String fullPath = requestPath.substring("/api/files/get/".length());
            
            String filePath = System.getProperty("user.dir") + uploadBasePath + "/" + fullPath;
            
            if (FileUtil.exist(filePath)) {
                byte[] bytes = FileUtil.readBytes(filePath);
                HttpHeaders headers = new HttpHeaders();
                headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode(FileUtil.getName(filePath), "UTF-8"));
                
                // 根据文件扩展名设置Content-Type
                String extension = FileUtil.extName(filePath).toLowerCase();
                MediaType mediaType = getMediaType(extension);
                headers.setContentType(mediaType);
                
                return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
            } else {
                return new ResponseEntity<>(HttpStatus.NOT_FOUND);
            }
        } catch (Exception e) {
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 删除文件
     *
     */
    @DeleteMapping("/**")
    public Result deleteFile() {
        try {
            // 获取完整的请求路径
            String requestPath = request.getRequestURI();
            // 移除 /api/files/ 前缀
            String fullPath = requestPath.substring("/api/files/".length());
            
            String filePath = System.getProperty("user.dir") + uploadBasePath + "/" + fullPath;
            if (FileUtil.exist(filePath)) {
                if (FileUtil.del(filePath)) {
                    return Result.success("删除成功");
                } else {
                    throw new CustomException("删除文件失败");
                }
            } else {
                throw new CustomException("文件不存在");
            }
        } catch (CustomException e) {
            throw e;
        } catch (Exception e) {
            throw new CustomException("删除文件失败: " + e.getMessage());
        }
    }

    /**
     * 批量删除文件
     * @param filePaths 文件路径列表
     * @return 删除结果
     */
    @PostMapping("/batchDelete")
    public Result batchDelete(@RequestBody List<String> filePaths) {
        synchronized (FileController.class) {
            // 1. 参数校验
            if (filePaths == null || filePaths.isEmpty()) {
                throw new CustomException("文件路径不能为空");
            }

            List<String> deletedFiles = new ArrayList<>();
            List<String> failedFiles = new ArrayList<>();

            // 2. 遍历处理每个文件
            for (String relativePath : filePaths) {
                try {
                    String fullPath = System.getProperty("user.dir") + uploadBasePath + "/" + relativePath;
                    
                    // 检查文件是否存在
                    if (FileUtil.exist(fullPath)) {
                        // 删除文件
                        if (FileUtil.del(fullPath)) {
                            deletedFiles.add(relativePath);
                        } else {
                            failedFiles.add(relativePath);
                        }
                    } else {
                        failedFiles.add(relativePath);
                    }
                } catch (Exception e) {
                    failedFiles.add(relativePath);
                }
            }

            // 3. 返回结果
            if (failedFiles.isEmpty()) {
                return Result.success(deletedFiles, "所有文件删除成功");
            } else {
                StringBuilder message = new StringBuilder();
                message.append("部分文件删除失败。成功删除: ").append(deletedFiles.size()).append("个，失败: ").append(failedFiles.size()).append("个");
                return Result.success(deletedFiles, message.toString());
            }
        }
    }

    /**
     * 替换式上传文件
     * @param file 新文件
     * @param oldFilePath 被替换文件的相对路径（例如：user/avatar/4/1749372257388_552.png）
     */
    @PostMapping(value = "/replace", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public Result replaceFile(@RequestParam("file") MultipartFile file, @RequestParam("oldFilePath") String oldFilePath) {
        synchronized (FileController.class) {
            // 1. 参数校验
            if (file == null || file.isEmpty()) {
                throw new CustomException("文件不能为空");
            }
            if (StrUtil.isBlank(oldFilePath)) {
                throw new CustomException("被替换文件路径不能为空");
            }

            // 2. 文件大小校验
            if (file.getSize() > maxFileSize) {
                throw new CustomException("文件大小超出限制");
            }

            // 3. 文件类型校验
            String originalFilename = file.getOriginalFilename();
            String extension = FileUtil.extName(originalFilename);
            if (!ALLOWED_EXTENSIONS.contains(extension.toLowerCase())) {
                throw new CustomException("不支持的文件类型");
            }

            try {
                // 4. 构建旧文件的完整路径
                String oldFullPath = System.getProperty("user.dir") + uploadBasePath + "/" + oldFilePath;
                
                // 5. 检查旧文件是否存在
                if (!FileUtil.exist(oldFullPath)) {
                    throw new CustomException("被替换的文件不存在");
                }

                // 6. 获取旧文件所在目录
                String oldDir = FileUtil.getParent(oldFullPath, 1);
                
                // 7. 生成新文件名（使用时间戳+随机数）
                String newFileName = System.currentTimeMillis() + "_" + (int)(Math.random() * 1000) + "." + extension;
                String newFullPath = oldDir + "/" + newFileName;

                // 8. 删除旧文件
                if (!FileUtil.del(oldFullPath)) {
                    throw new CustomException("删除旧文件失败");
                }

                // 9. 保存新文件
                FileUtil.writeBytes(file.getBytes(), newFullPath);
                
                // 10. 返回新文件的相对路径
                String newRelativePath = oldFilePath.substring(0, oldFilePath.lastIndexOf("/") + 1) + newFileName;
                return Result.success(newRelativePath);
            } catch (CustomException e) {
                throw e;
            } catch (Exception e) {
                throw new CustomException("文件替换失败: " + e.getMessage());
            }
        }
    }

    /**
     * 根据文件扩展名获取对应的MediaType
     */
    private MediaType getMediaType(String extension) {
        switch (extension) {
            case "jpg":
            case "jpeg":
                return MediaType.IMAGE_JPEG;
            case "png":
                return MediaType.IMAGE_PNG;
            case "gif":
                return MediaType.IMAGE_GIF;
            case "pdf":
                return MediaType.APPLICATION_PDF;
            case "doc":
            case "docx":
                return MediaType.parseMediaType("application/msword");
            case "xls":
            case "xlsx":
                return MediaType.parseMediaType("application/vnd.ms-excel");
            default:
                return MediaType.APPLICATION_OCTET_STREAM;
        }
    }
}
